/*
 * Copyright (c) GoKeep by gokeep.org. 2022-2023. All rights reserved
 */
package org.gokeep.communication.event;

import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.gokeep.common.component.SessionCacheComponent;
import org.gokeep.common.component.TokenComponent;
import org.gokeep.common.constant.enums.ClientTypeEnum;
import org.gokeep.common.dto.TokenPayload;
import org.gokeep.common.dto.UserAioSession;
import org.gokeep.common.util.SnowflakeIdWorker;
import org.gokeep.communication.message.MessageBuilder;
import org.gokeep.communication.proto.CommandProto;
import org.gokeep.communication.proto.MessageProto;
import org.redisson.api.RedissonClient;
import org.smartboot.socket.transport.AioSession;
import org.smartboot.socket.transport.WriteBuffer;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * 事件处理接口
 */
@Slf4j
public abstract class Event {
    /**
     * 暂存消息
     */
    protected MessageProto.Message message;
    /**
     * 暂存session
     */
    protected AioSession session;
    @Resource
    protected TokenComponent tokenComponent;
    @Resource
    protected SessionCacheComponent sessionCacheComponent;
    @Resource
    private RedissonClient redissonClient;


    public abstract void process(AioSession session, MessageProto.Message message);

    /**
     * 所有的事件均需要实现此方法来生命事件能接收的命令类型
     *
     * @return
     */
    protected abstract CommandProto.CommandEnum getEventType();


    /**
     * 事件执行逻辑
     *
     * @param session
     * @param message
     */
    public void execute(AioSession session, MessageProto.Message message) {
        this.session = session;
        this.message = message;
        if (getEventType().equals(message.getCommand())) {
             //生成消息的唯一序号
            this.message = generateMessageNumber(this.message);
            log.info("Event[{}] | username[{}] -> command[{}] -> serializeNo[{}]", this.session.getSessionID(), getUsername(), getEventType(), this.message.getSerializeNo());
            process(this.session, this.message);
        }
    }

    /**
     * 由服务器生成消息的唯一序号
     * @param message
     */
    private MessageProto.Message generateMessageNumber(MessageProto.Message message) {
        long serializeNo = SnowflakeIdWorker.generateId();
        return message.toBuilder().setSerializeNo(serializeNo).build();
    }

    /**
     * 获取Token, 仅事件子类该方法生效
     *
     * @return
     */
    protected String getToken() {
        return this.message.getToken();
    }

    /**
     * 获取TokenPayload
     *
     * @return
     */
    protected TokenPayload getTokenPayload() {
        return tokenComponent.verifyTokenGetPayload(this.getToken());
    }

    /**
     * 获取userId，仅事件子类该方法生效
     *
     * @return
     */
    protected String getUserId() {
        return getTokenPayload().getUserId();
    }

    /**
     * 获取用户名
     *
     * @return
     */
    protected String getUsername() {
        return getTokenPayload().getUsername();
    }
    /**
     * 获取客户端类型
     *
     * @return
     */
    protected ClientTypeEnum getClientType() {
        return getTokenPayload().getClientType();
    }

    /**
     * 写入数据
     * @param session
     * @param bytes
     */
    @SneakyThrows
    protected void write(AioSession session, byte[] bytes) {
        if (isOnline(session)) {
            WriteBuffer writeBuffer = session.writeBuffer();
            writeBuffer.writeInt(bytes.length);
            writeBuffer.writeAndFlush(bytes);
        }
    }

    /**
     * 写入数据
     *
     * @param bytes
     */
    @SneakyThrows
    protected void write(byte[] bytes) {
        write(this.session, bytes);
    }

    /**
     * 写入数据
     *
     * @param message
     */
    protected void write(MessageProto.Message message) {
        this.write(message.toByteArray());
    }

    /**
     * 写入数据
     *
     * @param message
     */
    protected void write(AioSession session, MessageProto.Message message) {
        this.write(session, message.toByteArray());
    }


    /**
     * 写入数据
     *
     * @param message
     */
    protected void write(UserAioSession userAioSession, MessageProto.Message message) {
        this.write(userAioSession.getSession(), message.toByteArray());
    }


    /**
     * 写入数据
     *
     * @param message
     */
    protected void write(List<UserAioSession> userAioSessions, MessageProto.Message message) {
        if (CollectionUtils.isEmpty(userAioSessions)) {
            return;
        }
        userAioSessions.stream().filter(this::isOnline).forEach(session1 -> write(session1.getSession(), message));
    }


    /**
     * 获取消息构建器
     * @return
     */
    protected MessageBuilder getMessageBuilder() {
        return MessageBuilder.with(this.message);
    }

    /**
     * 判断是否是在线的连接
     * @param userAioSession
     * @return
     */
    protected boolean isOnline(UserAioSession userAioSession) {
        return userAioSession != null && !userAioSession.getSession().isInvalid();
    }

    /**
     * 判断是否是在线的连接
     * @param aioSession
     * @return
     */
    protected boolean isOnline(AioSession aioSession) {
        return aioSession != null && !aioSession.isInvalid();
    }
}
